﻿using DocumentFormat.OpenXml.Lite.Core.Interfaces;
using DocumentFormat.OpenXml.Lite.Core.Office.VariantTypes;
using DocumentFormat.OpenXml.Lite.Core.Shared;
using DocumentFormat.OpenXml.Lite.Xml;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
using IO = System.IO;

namespace DocumentFormat.OpenXml.Lite.Core.Office
{
    public class AppProperties : XmlSerializable, ISerializable
    {
        const string VT = "http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes";
        const string ExtendedProps = "http://schemas.openxmlformats.org/officeDocument/2006/extended-properties";

        [XmlNamespaceDeclarations]
        public XmlSerializerNamespaces Namespaces { get; set; }

        #region Elements

        [Optional]
        [XmlElement("Template", Namespace = ExtendedProps)]
        public SimpleElement<string> Template { get; set; }

        [Optional]
        [XmlElement("Manager", Namespace = ExtendedProps)]
        public SimpleElement<string> Manager { get; set; }

        [Optional]
        [XmlElement("Company", Namespace = ExtendedProps)]
        public SimpleElement<string> Company { get; set; }

        [Optional]
        [XmlElement("Pages", Namespace = ExtendedProps)]
        public SimpleElement<int> Pages { get; set; }

        [Optional]
        [XmlElement("Words", Namespace = ExtendedProps)]
        public SimpleElement<int> Words { get; set; }

        [Optional]
        [XmlElement("Characters", Namespace = ExtendedProps)]
        public SimpleElement<int> Characters { get; set; }

        [Optional]
        [XmlElement("PresentationFormat", Namespace = ExtendedProps)]
        public SimpleElement<string> PresentationFormat { get; set; }

        [Optional]
        [XmlElement("Lines", Namespace = ExtendedProps)]
        public SimpleElement<int> Lines { get; set; }

        [Optional]
        [XmlElement("Paragraphs", Namespace = ExtendedProps)]
        public SimpleElement<int> Paragraphs { get; set; }

        [Optional]
        [XmlElement("Slides", Namespace = ExtendedProps)]
        public SimpleElement<int> Slides { get; set; }

        [Optional]
        [XmlElement("Notes", Namespace = ExtendedProps)]
        public SimpleElement<int> Notes { get; set; }

        [Optional]
        [XmlElement("TotalTime", Namespace = ExtendedProps)]
        public SimpleElement<int> TotalTime { get; set; }

        [Optional]
        [XmlElement("HiddenSlides", Namespace = ExtendedProps)]
        public SimpleElement<int> HiddenSlides { get; set; }

        [Optional]
        [XmlElement("MMClips", Namespace = ExtendedProps)]
        public SimpleElement<int> MMClips { get; set; }

        [Optional]
        [XmlElement("ScaleCrop", Namespace = ExtendedProps)]
        public SimpleElement<bool> ScaleCrop { get; set; }

        [Optional]
        [XmlElement("HeadingPairs", Namespace = ExtendedProps)]
        public VectorContainer HeadingPairs { get; set; }

        [Optional]
        [XmlElement("TitlesOfParts", Namespace = ExtendedProps)]
        public VectorContainer TitlesOfParts { get; set; }

        [Optional]
        [XmlElement("LinksUpToDate", Namespace = ExtendedProps)]
        public SimpleElement<bool> LinksUpToDate { get; set; }

        [Optional]
        [XmlElement("CharactersWithSpaces", Namespace = ExtendedProps)]
        public SimpleElement<int> CharactersWithSpaces { get; set; }

        [Optional]
        [XmlElement("SharedDoc", Namespace = ExtendedProps)]
        public SimpleElement<bool> SharedDoc { get; set; }

        [Optional]
        [XmlElement("HyperlinkBase", Namespace = ExtendedProps)]
        public SimpleElement<string> HyperlinkBase { get; set; }

        [Optional]
        [XmlElement("HLinks", Namespace = ExtendedProps)]
        public VectorContainer HLinks { get; set; }

        [Optional]
        [XmlElement("HyperlinksChanged", Namespace = ExtendedProps)]
        public SimpleElement<bool> HyperlinksChanged { get; set; }

        [Optional]
        [XmlElement("DigSig", Namespace = ExtendedProps)]
        public SimpleElement<BinaryBlob> DigSig { get; set; }

        [Optional]
        [XmlElement("Application", Namespace = ExtendedProps)]
        public SimpleElement<string> Application { get; set; }

        [Optional]
        [XmlElement("AppVersion", Namespace = ExtendedProps)]
        public SimpleElement<string> AppVersion { get; set; }

        [Optional]
        [XmlElement("DocSecurity", Namespace = ExtendedProps)]
        public SimpleElement<int> DocSecurity { get; set; }

        #endregion

        public AppProperties()
        {
            Namespaces = new XmlSerializerNamespaces();
            Namespaces.Add("", ExtendedProps);
            Namespaces.Add("vt", VT);
        }

        #region Public Methods

        public byte[] Serialize()
        {
            XmlSerializer serializer = new XmlSerializer(this.GetType());
            using (var stream = new IO.MemoryStream())
            {
                using (var writer = new IO.StreamWriter(stream, Encoding.UTF8))
                {
                    using (var xwriter = XmlWriter.Create(writer))
                    {
                        xwriter.WriteStartElement("", "Properties", ExtendedProps);
                        foreach (var ns in Namespaces.ToArray())
                        {
                            if (ns.Name != "")
                            {
                                xwriter.WriteAttributeString("xmlns", ns.Name, null, ns.Namespace);
                            }
                        }
                        this.WriteXml(xwriter);
                    }
                    return stream.ToArray();
                }
            }
        }

        public void Deserialize(System.IO.Stream content)
        {
            using (var reader = XmlReader.Create(content))
            {
                reader.ReadToDescendant("Properties", ExtendedProps);
                this.ReadXml(reader);
            }
        }

        #endregion
    }
}
